package com.plian.system.service.pf.impl;

import com.alibaba.fastjson.JSON;
import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper;
import com.baomidou.mybatisplus.core.conditions.query.QueryWrapper;
import com.baomidou.mybatisplus.core.metadata.IPage;
import com.plian.Tools.*;
import com.plian.Tools.pagedata.PageData;
import com.plian.system.cache.UserCache;
import com.plian.system.common.status.CheckStatus;
import com.plian.system.constant.sys.FormStatusConstant;
import com.plian.system.constant.sys.FormTypeConstant;
import com.plian.system.constant.yth.YthConstant;
import com.plian.system.entity.pf.BaseEnterpriseAnnuity;
import com.plian.system.entity.pf.EnterpriseAnnuityDetail;
import com.plian.system.entity.sys.ApprovalMessage;
import com.plian.system.entity.sys.Org;
import com.plian.system.mapper.pf.BaseEnterpriseAnnuityMapper;
import com.plian.system.model.CommonCode;
import com.plian.system.model.ListResult;
import com.plian.system.model.R;
import com.plian.system.mybatis.base.BaseFlowService;
import com.plian.system.mybatis.base.BaseServiceImpl;
import com.plian.system.mybatis.search.SearchEntity;
import com.plian.system.mybatis.search.SearchParamEntiy;
import com.plian.system.mybatis.search.TokenSearch;
import com.plian.system.mybatis.support.Condition;
import com.plian.system.mybatis.support.Query;
import com.plian.system.service.pf.IBaseEnterpriseAnnuityService;
import com.plian.system.service.pf.IEnterpriseAnnuityDetailService;
import com.plian.system.service.sys.code.IFormCodeService;
import com.plian.system.service.sys.file.FileService;
import com.plian.system.service.sys.message.IApprovalMessageService;
import com.plian.system.service.sys.orgzation.IOrgService;
import com.plian.system.service.wf.FormWorkflowService;
import com.plian.system.vo.pf.BaseEnterpriseAnnuityVO;
import com.plian.system.vo.yth.YthResult;
import com.plian.system.wrapper.pf.BaseEnterpriseAnnuityWrapper;
import lombok.AllArgsConstructor;
import lombok.extern.slf4j.Slf4j;
import org.apache.commons.lang.exception.ExceptionUtils;
import org.apache.commons.lang3.StringUtils;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;
import org.springframework.web.bind.annotation.RequestBody;

import java.util.*;
import java.util.stream.Collectors;

import static com.plian.system.constant.sys.ApprovalMessageTypeConstant.GZW_TYPE;
import static com.plian.system.constant.sys.FormStatusConstant.UNREVIEWED;
import static com.plian.system.constant.sys.FormTypeConstant.PF_ENTERPRISE_ANNUITY;

/**
 * @Description: TODO
 * @Author: Take-off
 * @Date: 2023/3/13 10:09 AM
 * @Param
 * @return
 * @Version: 1.0
 **/
@Slf4j
@Service
@AllArgsConstructor
public class BaseEnterpriseAnnuityServiceImpl extends BaseServiceImpl<BaseEnterpriseAnnuityMapper,BaseEnterpriseAnnuity> implements IBaseEnterpriseAnnuityService, BaseFlowService {

    private IEnterpriseAnnuityDetailService detailService;

    private FormWorkflowService formWorkflowService;

    private IFormCodeService formCodeService;

    private FileService fileService;

    private BaseEnterpriseAnnuityWrapper baseEnterpriseAnnuityWrapper;

    private IOrgService orgService;

    private IApprovalMessageService approvalMessageService;

    @Override
    public boolean saveOrUpdate(BaseEnterpriseAnnuity baseEnterpriseAnnuity) {
        boolean flag = false;
        if (!Optional.ofNullable(baseEnterpriseAnnuity.getStatus()).isPresent()) {
            baseEnterpriseAnnuity.setStatus(FormStatusConstant.UNREVIEWED);
        }
        if (baseEnterpriseAnnuity.getStatus().equals(FormStatusConstant.REJECT)) {
            baseEnterpriseAnnuity.setStatus(FormStatusConstant.UNREVIEWED);
        }
        if (!Optional.ofNullable(baseEnterpriseAnnuity.getId()).isPresent()) {
            flag = true;
            baseEnterpriseAnnuity.setCode(formCodeService.getCode(FormTypeConstant.PF_ENTERPRISE_ANNUITY));
            baseEnterpriseAnnuity.setFormType(String.valueOf(FormTypeConstant.PF_ENTERPRISE_ANNUITY));
        }

        boolean result =super.saveOrUpdate(baseEnterpriseAnnuity);
        if (flag){
            fileService.saveAll(String.valueOf(baseEnterpriseAnnuity.getId()), baseEnterpriseAnnuity.getDocList());
        }else {
            fileService.edit(String.valueOf(baseEnterpriseAnnuity.getId()), baseEnterpriseAnnuity.getDocList());
        }
        if (StringUtil.isNotBlank(baseEnterpriseAnnuity.getAttachIds())){
            fileService.upYthFile(baseEnterpriseAnnuity.getAttachIds(),String.valueOf(baseEnterpriseAnnuity.getId()));
        }
        return result;
    }

    @Override
    @Transactional(rollbackFor=RuntimeException.class)
    public boolean deleteLogic(List<Long> ids) {
        for (Long id : ids) {
            BaseEnterpriseAnnuity baseEnterpriseAnnuity = getById(id);
            if (baseEnterpriseAnnuity == null) {
                return false;
            } else if (baseEnterpriseAnnuity.getStatus() != null &&
                    (baseEnterpriseAnnuity.getStatus() != FormStatusConstant.STASH && baseEnterpriseAnnuity.getStatus() != FormStatusConstant.UNREVIEWED)) {
                return false;
            }
            formWorkflowService.deleteProcessInstance(String.valueOf(id));
        }

        boolean result = super.deleteLogic(ids);
        if (result){
            detailService.deleteByParentId(ids);
        }
        return result;
    }

    @Override
    public HashMap<String,Object> commit(String id) {
        handleStatus(Long.valueOf(id), FormStatusConstant.FLOW,null);

        //将需要提交的流程变量返回，用于工作流侧
        return new HashMap<String,Object>();
    }

    @Override
    public Boolean finish(String id) {
        return handleStatus(Long.valueOf(id), FormStatusConstant.FINISH,"审批通过");
    }

    @Override
    public Boolean reject(String id, int formState,String comment) {
        return handleStatus(Long.valueOf(id), formState,comment);
    }

    @Override
    public List<PageData> findByIds(List<String> formIds) {
        LambdaQueryWrapper<BaseEnterpriseAnnuity> queryWrapper = new LambdaQueryWrapper<>();
        queryWrapper.in(BaseEnterpriseAnnuity::getId, Func.toLongList(StringUtils.join(formIds, StringPool.COMMA)));
        List<BaseEnterpriseAnnuity> baseDeputyDifferents = list(queryWrapper);
        List<BaseEnterpriseAnnuityVO> baseEnterpriseAnnuityVOS = baseEnterpriseAnnuityWrapper.entityToVO(baseDeputyDifferents);
        List<PageData> pageDataList = new ArrayList<>();
        try{
            if (CollectionUtil.isNotEmpty(baseEnterpriseAnnuityVOS)){
                for (BaseEnterpriseAnnuityVO vo : baseEnterpriseAnnuityVOS){
                    PageData pd = new PageData();
                    pd.put("id", vo.getId());
                    pd.put("UNITNAME", vo.getFillingUnitName());
                    pd.put("APPLICANTNAME", vo.getCreateUserName());
                    pd.put("applicantId", vo.getCreateUser());
                    pd.put("applyOrganizationId", vo.getFillingUnitId());
                    pd.put("formType", vo.getFormType());
                    pd.put("orgName", vo.getFillingUnitName());
                    pageDataList.add(pd);
                }
            }

            return pageDataList;
        } catch (Exception e) {
            log.error(ExceptionUtils.getFullStackTrace(e));
        }
        return pageDataList;
    }

    @Override
    public List<Integer> getFormType() {
        return Arrays.asList(PF_ENTERPRISE_ANNUITY);
    }

    @Override
    public void goBackToStash(String formId) {
        handleStatus(Long.valueOf(formId), UNREVIEWED,null);
    }

    /**
     * 统一处理状态机事件方法
     *
     * @param id          主键
     * @param updateStatus  更新状态
     * @return boolean
     */
    private Boolean handleStatus(Long id, int updateStatus,String comment) {
        try {
            BaseEnterpriseAnnuity baseEnterpriseAnnuity = getById(id);
            /**
             * 设置审批人和审批时间
             */
            if (updateStatus == FormStatusConstant.FINISH){
                baseEnterpriseAnnuity.setApprovedUser(TokenUtil.getTokenUserId());
                Date now = DateUtil.now();
                baseEnterpriseAnnuity.setApprovedTime(now);
            }
            if (StringUtil.isNotBlank(baseEnterpriseAnnuity.getDataSource()) &&
                    StringUtil.isNotBlank(baseEnterpriseAnnuity.getDataSourceId())){
                if (updateStatus == FormStatusConstant.FINISH || updateStatus == FormStatusConstant.REJECT){
                    ApprovalMessage approvalMessage = new ApprovalMessage();
                    approvalMessage.setDataSourceId(baseEnterpriseAnnuity.getDataSourceId());
                    approvalMessage.setOpinion(comment);
                    approvalMessage.setIsApprove(updateStatus == FormStatusConstant.FINISH ? 2 : 1);
                    approvalMessage.setIsSend(1);
                    approvalMessage.setDataSourceType(GZW_TYPE);

                    if (baseEnterpriseAnnuity.getDataSource().equals(YthConstant.DATA_NINGBO)) {
                        approvalMessage.setDataSourceType(YthConstant.DATA_NINGBO);
                        approvalMessage.setFilingUserName(UserCache.userIdToName(TokenUtil.getTokenUserId()));
                        approvalMessage.setFormType(FormTypeConstant.PF_ENTERPRISE_ANNUITY);
                        approvalMessage.setFilingCode(baseEnterpriseAnnuity.getCode());
                    }
                    approvalMessageService.save(approvalMessage);
                }
            }

            baseEnterpriseAnnuity.setStatus(updateStatus);
            updateById(baseEnterpriseAnnuity);
            return true;
        } catch (Exception e) {
            log.error(ExceptionUtils.getFullStackTrace(e));
            return false;
        }
    }

    @Override
    @Transactional(rollbackFor=RuntimeException.class)
    public boolean submit(BaseEnterpriseAnnuity baseEnterpriseAnnuity) {
        boolean result = saveOrUpdate(baseEnterpriseAnnuity);
        if (result){
            List<EnterpriseAnnuityDetail> details = baseEnterpriseAnnuity.getEnterpriseAnnuityDetails();
            if (CollectionUtil.isNotEmpty(details)){
                for (EnterpriseAnnuityDetail detail : details){
                    if (detail.getId() != null &&
                            Optional.ofNullable(detail.getIsDeleted()).isPresent() && detail.getIsDeleted().intValue() == 1) {
                        detailService.removeById(detail.getId());
                    }else {
                        detail.setBaseId(baseEnterpriseAnnuity.getId());
                        detailService.saveOrUpdate(detail);
                    }
                }
            }
        }
        return result;
    }

    @Override
    public R<BaseEnterpriseAnnuityVO> getDetailObj(BaseEnterpriseAnnuity baseEnterpriseAnnuity) {
        BaseEnterpriseAnnuity one = getOne(Condition.getQueryWrapper(baseEnterpriseAnnuity));
        BaseEnterpriseAnnuityVO baseEnterpriseAnnuityVO = baseEnterpriseAnnuityWrapper.entityToVO(one);
        if (Optional.ofNullable(baseEnterpriseAnnuityVO).isPresent()){
            List<EnterpriseAnnuityDetail> details = detailService.list(new LambdaQueryWrapper<EnterpriseAnnuityDetail>().eq(EnterpriseAnnuityDetail::getBaseId, baseEnterpriseAnnuityVO.getId()));
            baseEnterpriseAnnuityVO.setEnterpriseAnnuityDetails(details);
        }
        return R.data(baseEnterpriseAnnuityVO);
    }

    @Override
    public ListResult<BaseEnterpriseAnnuityVO> list(@RequestBody Query query) {
        List<SearchEntity> entityList = query.getSearch();
        if (query.getAscs()==null&&query.getDescs()==null){
            query.setDescs("create_time");
        }
        QueryWrapper<BaseEnterpriseAnnuity> queryWrapper = SearchParamEntiy.getQueryWrapper(
                Condition.getQueryWrapper(new BaseEnterpriseAnnuity()), entityList
        );

        TokenSearch<BaseEnterpriseAnnuity> tokenSearch = new TokenSearch<>();
		tokenSearch.addTokenQuery(queryWrapper, query);

        IPage<BaseEnterpriseAnnuity> pages = page(Condition.getPage(query), queryWrapper);
        List<BaseEnterpriseAnnuityVO> baseEnterpriseAnnuityVOS = baseEnterpriseAnnuityWrapper.entityToVO(pages.getRecords());
        ListResult<BaseEnterpriseAnnuityVO> listResult = new ListResult<>(CommonCode.SUCCESS);
        listResult.setList(baseEnterpriseAnnuityVOS);
        listResult.setTotal(Long.valueOf(pages.getTotal()).intValue());
        return listResult;
    }

    @Override
    public String saveEnterpriseAnnuity(String data){
        YthResult ythResult = new YthResult();
        List<String> successIds = new ArrayList<>();
        List<String> failIds = new ArrayList<>();
        List<String> failReasons = new ArrayList<>();
        //将json字符串转换成list
        List<BaseEnterpriseAnnuity> dataList = JSON.parseArray(data, BaseEnterpriseAnnuity.class);
        if (CollectionUtil.isNotEmpty(dataList)){
            //组织map
            Map<String, String> orgSourceMap = orgService.getSourceId();
            //根据datasourceIds 查询出所有的数据
            List<BaseEnterpriseAnnuity> list = list(new LambdaQueryWrapper<BaseEnterpriseAnnuity>().in(BaseEnterpriseAnnuity::getDataSourceId, dataList.stream().map(BaseEnterpriseAnnuity::getDataSourceId).toArray()));
            if (CollectionUtil.isNotEmpty(list)){
                //删除子集
                List<Long> ids = list.stream().map(BaseEnterpriseAnnuity::getId).collect(Collectors.toList());
                detailService.remove(new LambdaQueryWrapper<EnterpriseAnnuityDetail>().in(EnterpriseAnnuityDetail::getBaseId, ids));
            }
            //如果数据库中有数据，就更新，没有就新增
            for (BaseEnterpriseAnnuity entity:dataList){
                transfer(entity,orgSourceMap);
                //id重复略过
                if (CollectionUtil.isNotEmpty(list)){
                    List<String> olIds = list.stream().map(BaseEnterpriseAnnuity::getDataSourceId).collect(Collectors.toList());
                    String dataSourceId = entity.getDataSourceId();
                    //判断数据库中是否有数据
                    if (olIds.contains(dataSourceId)){
                        for (BaseEnterpriseAnnuity oldEntity:list){
                            if (dataSourceId.equals(oldEntity.getDataSourceId())){
                                //判断status是否为0，如果是0，就更新，不是0，就不更新
                                if (CheckStatus.checkCode(oldEntity.getStatus())){
                                    successIds.add(dataSourceId);
                                    entity.setId(oldEntity.getId());
                                    entity.setDataSource(YthConstant.DATA_NINGBO);
                                    submit(entity);
                                    list.remove(oldEntity);
                                    break;
                                }else {
                                    failIds.add(dataSourceId);
                                    failReasons.add("dataSourceId:"+dataSourceId+"数据已提交且已经在流程中，无法更新");
                                    break;
                                }
                            }
                        }
                    }else {
                        //如果数据库中没有数据，就新增
                        entity.setDataSource(YthConstant.DATA_NINGBO);
                        submit(entity);
                        successIds.add(entity.getDataSourceId());
                    }
                }else {
                    //如果数据库中没有数据，就新增
                    entity.setDataSource(YthConstant.DATA_NINGBO);
                    submit(entity);
                    successIds.add(entity.getDataSourceId());
                }
            }
        } else {
            failReasons.add("数据为空");
        }
        ythResult.setSuccessIds(successIds);
        ythResult.setFailIds(failIds);
        ythResult.setFailReason(StringUtils.join(failReasons, ";"));
        //ythResult转换成json字符串
        return JSON.toJSONString(ythResult);
    }

    private void transfer(BaseEnterpriseAnnuity entity, Map<String, String> orgSourceMap){
        Optional.ofNullable(entity.getFillingUnitId()).ifPresent(m ->
                {
                    String orgId = orgSourceMap.get(m);
                    if (StringUtil.isNotBlank(orgId)){
                        entity.setFillingUnitId(orgId);
                        entity.setCreateCompanyId(orgId);
                         Org org = orgService.getById(orgId);
                        List<EnterpriseAnnuityDetail> enterpriseAnnuityDetails = entity.getEnterpriseAnnuityDetails();
                        if (CollectionUtil.isNotEmpty(enterpriseAnnuityDetails)){
                            enterpriseAnnuityDetails.forEach(detail ->{
                                detail.setOrgId(orgId);
                                detail.setOrgName(org.getName());
                            });
                        }
                    }
                }
        );
    }

}
